import JSON5 from "json5";
import {HvigorNode} from "@ohos/hvigor";
import path from "path";
import fs from "fs";

/**
 * 格式化时间戳
 */
export function formatTimestamp(d = new Date()): string {
    const yyyy = d.getFullYear();
    const MM = String(d.getMonth() + 1).padStart(2, '0');
    const dd = String(d.getDate()).padStart(2, '0');
    const hh = String(d.getHours()).padStart(2, '0');
    const mm = String(d.getMinutes()).padStart(2, '0');
    const ss = String(d.getSeconds()).padStart(2, '0');
    return `${yyyy}${MM}${dd}_${hh}${mm}${ss}`;
}

/** 背景色为绿色 */
export function blackBackgroundGreenTextLog(text: string) {
    console.log(BG(text));
}

/** 背景色为黄色 */
export function blackBackgroundYellowTextLog(text: string) {
    console.log(BY(text));
}

/** 背景色为红色 */
export function blackBackgroundRedTextLog(text: string) {
    console.log(BR(text));
}

export function BG(text: string): string {
    return `\x1b[32;40;1m${text}\x1b[0m`;
}

/** 控制台输出黑色背景 红色字 */
export function BY(text: string): string {
    return `\x1b[33;40;1m${text}\x1b[0m`;
}


/** 控制台输出黑色背景 红色字 */
export function BR(text: string): string {
    return `\x1b[31;40;1m${text}\x1b[0m`;
}

/** 深度优先收集“pkg 的前置依赖”（去重 + 拓扑顺序，不含 pkg 本身） */
export function collectDeps(
    pkg: string,
    graph: Map<string, string[]>
): string[] {
    const visited = new Set<string>();   // 已完成节点
    const visiting = new Set<string>();  // 本次路径上的节点（用于环检测）
    const order: string[] = [];

    const dfs = (node: string) => {
        if (node === 'entry') return;            // 显式排除 entry
        if (visited.has(node)) return;
        if (visiting.has(node)) {
            console.warn(`[har-sdk-build-plugin] 检测到循环依赖: ${node} <-> ...`);
            return; // 检测到环，直接返回，避免死递归
        }
        visiting.add(node);
        const deps = graph.get(node) ?? [];
        for (const d of deps) dfs(d);
        visiting.delete(node);
        visited.add(node);
        order.push(node); // 依赖先入栈，当前节点后入栈 => 拓扑序
    };

    for (const dep of (graph.get(pkg) ?? [])) {
        dfs(dep);
    }
    return order;
}

/** 计算全量拓扑序（排除 entry），用于 topoMap 的 "all" */
function topoSortAll(graph: Map<string, string[]>): string[] {
    const visited = new Set<string>();
    const visiting = new Set<string>();
    const order: string[] = [];

    const dfs = (node: string) => {
        if (node === 'entry') return;
        if (visited.has(node)) return;
        if (visiting.has(node)) {
            console.warn(`[har-sdk-build-plugin] 检测到循环依赖: ${node} <-> ...`);
            return;
        }
        visiting.add(node);
        for (const d of (graph.get(node) ?? [])) dfs(d);
        visiting.delete(node);
        visited.add(node);
        order.push(node);
    };

    // 对图中所有节点做 DFS，得到一个全量拓扑序
    for (const node of graph.keys()) dfs(node);
    // 再保险过滤一次 entry（正常不会在内）
    return order.filter(n => n !== 'entry');
}

export function getModelTopoMap(root: HvigorNode): Map<string, string[]> {
    // 1) 构建 “包名 → 直接 file: 依赖” 图（Map 版本）
    const graph = new Map<string, string[]>();
    root.subNodes(sub => {
        const pkgPath = path.join(sub.getNodePath(), 'oh-package.json5');
        if (!fs.existsSync(pkgPath)) return;
        const pkgJson: any = JSON5.parse(fs.readFileSync(pkgPath, 'utf-8'));
        const deps = Object.entries<string>(pkgJson.dependencies ?? {})
            .filter(([, spec]) =>
                spec.startsWith('file:') &&
                !spec.trim().toLowerCase().endsWith('.har')
            )
            .map(([name]) => name);
        graph.set(pkgJson.name, deps);
    });

    // 2) 构建拓扑 map：每个模块 → 其前置依赖的拓扑顺序
    const topoMap = new Map<string, string[]>();
    for (const pkg of graph.keys()) {
        topoMap.set(pkg, collectDeps(pkg, graph));
    }

    // 3) "all" → 全量拓扑顺序（排除 entry）
    topoMap.set('all', topoSortAll(graph));

    return topoMap;
}

export function printDepsMap(root: HvigorNode, fullTarget?: string) {
    const topoMap = getModelTopoMap(root);

    if (fullTarget) {
        if (!topoMap.has(fullTarget)) {
            console.log(`[har-sdk-build-plugin] 未找到模块 ${fullTarget}`);
            return;
        }
        const order = [...(topoMap.get(fullTarget) ?? []), fullTarget];
        console.log(`[har-sdk-build-plugin] 模块 ${fullTarget} 编译顺序：`);
        console.log(JSON.stringify(order, null, 2));
    } else {
        console.log(BG('[har-sdk-build-plugin] 本地依赖拓扑映射：'));
        // Map -> 普通对象便于打印
        const obj = Object.fromEntries([...topoMap.entries()]);
        console.log(JSON.stringify(obj, null, 2));
    }
}

/**
 * 判断是否跳过某个模块
 * @param moduleName 当前模块名
 * @param targetModule 编译目标模块名
 * @param topoMap 模块拓扑映射
 * @returns true 表示跳过该模块，false 表示需要参与编译
 */
export function shouldSkipModule(
    moduleName: string,
    targetModule: string,
    topoMap: Map<string, string[]>
): boolean {
    // 如果目标模块不在拓扑图中，直接跳过
    if (!topoMap.has(targetModule)) {
        return true;
    }

    // 取目标模块的依赖链
    const deps = topoMap.get(targetModule) ?? [];

    // 如果当前模块既不是目标模块本身，也不在依赖链中，则跳过
    if (moduleName !== targetModule && !deps.includes(moduleName)) {
        return true;
    }

    return false;
}
